package fileserver

import (
	"fmt"
	"html/template"
	"io/ioutil"
	"net"
	"net/http"
	"os"
	"path/filepath"
	"sort"
	"strings"
	"time"

	"github.com/gin-gonic/gin"
)

type Service interface {
	StartFileService()
	getLocalIP() error
	listFiles(*gin.Context)
	formatSize(float64) string
	loadTemplate() (*template.Template, error)
}

type Dir struct {
	FilesPath   string
	localIpaddr []string
	Port        string
}

func (d *Dir) loadTemplate() (*template.Template, error) {
	t := template.New("")
	for name, file := range Assets.Files {
		if file.IsDir() || !strings.HasSuffix(name, ".html") {
			continue
		}
		h, err := ioutil.ReadAll(file)
		if err != nil {
			return nil, err
		}
		t, err = t.New(name).Parse(string(h))
		if err != nil {
			return nil, err
		}
	}
	return t, nil
}

// 处理显示的单位
func (d *Dir) formatSize(sizeMB float64) string {
	switch {
	case sizeMB < 1:
		sizeKB := sizeMB * 1024
		return fmt.Sprintf("%.2f KB", sizeKB)
	case sizeMB < 1024:
		return fmt.Sprintf("%.2f MB", sizeMB)
	default:
		sizeGB := sizeMB / 1024
		return fmt.Sprintf("%.2f GB", sizeGB)
	}
}

// 获取本机ip地址并赋值给结构体
func (d *Dir) getLocalIP() error {
	addrs, err := net.InterfaceAddrs()
	if err != nil {
		return err
	}
	d.localIpaddr = make([]string, 0)
	for _, address := range addrs {
		// 检查是否为IP地址，并且不是回环地址

		if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
			// 确保是IPv4地址
			if ipnet.IP.To4() != nil {
				// 排除172开头的地址
				if ipnet.IP.To4()[0] != 172 {
					d.localIpaddr = append(d.localIpaddr, string(ipnet.IP.String()))
				}
			}
		}
	}
	return fmt.Errorf("未能找到非回环的IPv4地址")
}

// 识别文件目录内容
func (d *Dir) listFiles(c *gin.Context) {
	root := d.FilesPath // 根据实际情况调整此路径
	relPath := c.Param("filepath")
	if relPath == "/" {
		relPath = ""
	}

	// 根据路径获取文件信息
	fsPath := filepath.Join(root, relPath)
	fileInfos, err := os.ReadDir(fsPath)
	if err != nil {
		c.String(http.StatusNotFound, "Directory not found.")
		return
	}

	// 维护文件列表信息
	fileList := make([]map[string]interface{}, 0)
	for _, fileInfo := range fileInfos {
		info, err := fileInfo.Info()
		if err != nil {
			continue // 如果无法获取信息，则跳过该文件/目录
		}
		sizeMB := float64(info.Size()) / (1024 * 1024)

		item := map[string]interface{}{
			"Name":     fileInfo.Name(),
			"IsDir":    fileInfo.IsDir(),
			"Size":     d.formatSize(sizeMB),
			"ModTime":  info.ModTime().Format(time.DateTime),
			"FullPath": filepath.Join(relPath, fileInfo.Name()),
		}
		if fileInfo.IsDir() {
			if os.PathSeparator == '\\' {
				item["URL"] = filepath.ToSlash(filepath.Join("./list/", item["FullPath"].(string))) + "/"
			} else {
				item["URL"] = filepath.Join("./list/", item["FullPath"].(string)) + "/"
			}
		} else {
			if os.PathSeparator == '\\' {
				item["URL"] = filepath.ToSlash(filepath.Join("./api/v1/download/", item["FullPath"].(string)))
			} else {
				item["URL"] = filepath.Join("./api/v1/download/", item["FullPath"].(string))
			}

		}
		fileList = append(fileList, item)
	}

	// 对文件列表进行排序，文件夹排在前面，按字母顺序排序
	sort.Slice(fileList, func(i, j int) bool {
		if fileList[i]["IsDir"].(bool) && !fileList[j]["IsDir"].(bool) {
			return true
		}
		if !fileList[i]["IsDir"].(bool) && fileList[j]["IsDir"].(bool) {
			return false
		}
		return strings.ToLower(fileList[i]["Name"].(string)) < strings.ToLower(fileList[j]["Name"].(string))
	})

	c.HTML(
		http.StatusOK,
		"/templates/index.html",
		gin.H{
			"Files":      fileList,
			"CurrentDir": relPath,
		},
	)
}

// 启动http服务
func (d *Dir) StartFileService() {
	// 开启上线模式
	gin.SetMode(gin.ReleaseMode)

	// 默认是Debug模式
	r := gin.Default()

	// 获取系统ip地址
	d.getLocalIP()

	// 加载HTML模板
	// r.LoadHTMLGlob("./templates/*")

	t, err := d.loadTemplate()
	if err != nil {
		panic(err)
	}
	r.SetHTMLTemplate(t)

	r.StaticFS("/api/v1/download", http.Dir(d.FilesPath))

	r.GET("/", func(c *gin.Context) {
		c.Redirect(http.StatusMovedPermanently, "/list/")
	})

	// 路由到处理函数
	r.GET("/list/*filepath", d.listFiles)

	fmt.Printf("Download service filePath：%s\n", d.FilesPath)

	for _, ipaddress := range d.localIpaddr {
		fmt.Printf("Service URL: http://%s:%s\n", ipaddress, d.Port)
	}

	// 启动HTTP服务
	if err := r.Run("0.0.0.0:" + d.Port); err != nil {
		fmt.Println(err.Error())
	}
}
